package ac.beiwo.baas.user.service;

import ac.beiwo.baas.common.entity.SimpleCode;
import ac.beiwo.baas.common.entity.SimpleError;
import ac.beiwo.baas.object.entity.BaasObject;
import ac.beiwo.baas.object.entity.BaasQuery;
import ac.beiwo.baas.object.service.ObjectService;
import ac.beiwo.baas.user.entity.BaasUser;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.UUID;

/**
 * Created by Staryet on 15/8/13.
 */
@Service
public class UserService {

    public static String USER_CLASS_NAME = "_User";
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ObjectService objectService;

    public String register(BaasUser user) throws SimpleError {
        String username = user.getUsername();
        String password = user.getPassword();
        if (StringUtils.isEmpty(password)) {
            //密码禁止为空
            throw new SimpleError(SimpleCode.USER_EMPTY_PASSWORD);
        }
        BaasUser exist = get(username);
        if (exist != null) {
            //用户已存在
            throw new SimpleError(SimpleCode.USER_ALREADY_EXIST);
        }
        user.setPassword(encrypt(username, password));
        user.setSessionToken(getSessionToken());
        //禁止设置ACL字段
        user.remove("acl");
        return objectService.insert(USER_CLASS_NAME, user, null, true);
    }

    /**
     * 获取用户
     *
     * @param username 用户名
     * @return 用户
     * @throws SimpleError
     */
    public BaasUser get(String username) throws SimpleError {
        BaasQuery query = new BaasQuery();
        query.put("username", username);
        List<BaasObject> users = objectService.list(USER_CLASS_NAME, query, null, null, 1, 0, null, false);
        if (users.size() == 0) {
            return null;
        }
        return new BaasUser(users.get(0));
    }

    /**
     * 用户登录
     *
     * @param username 用户名
     * @param password 密码
     */
    public BaasUser login(String username, String password) throws SimpleError {
        if (StringUtils.isEmpty(password)) {
            //密码禁止为空
            throw new SimpleError(SimpleCode.USER_EMPTY_PASSWORD);
        }
        BaasUser user = get(username);
        if (user == null) {
            throw new SimpleError(SimpleCode.USER_NOT_EXIST);
        }
        String passwordMd5 = DigestUtils.md5DigestAsHex((username + "_._" + password).getBytes());
        String passwordExist = user.getPassword();
        if (!passwordMd5.equals(passwordExist)) {
            //密码错误
            throw new SimpleError(SimpleCode.USER_WRONG_PASSWORD);
        }
        user.setPassword("");
        return user;
    }

    public void update(String id, BaasUser user, BaasUser currentUser, boolean isMaster) throws SimpleError {
        if (!isMaster) {
            if (currentUser == null || !currentUser.getId().equals(id)) {
                //非本人禁止修改用户信息
                throw new SimpleError(SimpleCode.USER_NOT_MATCH);
            }
            user.remove("phone");
            user.remove("email");
            String newPassword = user.getPassword();
            if (!StringUtils.isEmpty(newPassword)) {
                //密码字段不为空
                String newPasswordEncrypt = encrypt(currentUser.getUsername(), user.getPassword());
                if (!newPasswordEncrypt.equals(currentUser.getPassword())) {
                    //密码字段被修改 更新SessionToken
                    user.setPassword(newPasswordEncrypt);
                    String sessionTokenNow = currentUser.getSessionToken();
                    if (!StringUtils.isEmpty(sessionTokenNow)) {
                        deleteUserCache(sessionTokenNow);
                    }
                    user.setSessionToken(getSessionToken());
                }
            }
        }
        //禁止修改用户名
        user.remove("username");
        //禁止修改ACL字段
        user.remove("acl");
        objectService.update(UserService.USER_CLASS_NAME, id, user, null, true);
    }

    public String encrypt(String username, String password) {
        return DigestUtils.md5DigestAsHex((username + "_._" + password).getBytes());
    }

    /**
     * 获取当前用户
     *
     * @return 当前用户
     */
    public BaasUser getCurrentUser(HttpServletRequest request) throws SimpleError {
        String sessionToken = request.getHeader("SessionToken");
        if (sessionToken == null) {
            return null;
        } else {
            return getUserBySessionToken(sessionToken);
        }
    }

    public BaasUser getUserBySessionToken(String sessionToken) throws SimpleError {
        BaasUser userCache = getUserCache(sessionToken);
        if (userCache == null) {
            //未找到缓存 查询用户数据
            BaasQuery query = new BaasQuery();
            query.put("sessionToken", sessionToken);
            List<BaasObject> users = objectService.list(USER_CLASS_NAME, query, null, null, 1, 0, null, true);
            if (users.size() == 0) {
                return null;
            }
            BaasUser user = new BaasUser(users.get(0));
            setUserCache(sessionToken, user);
            return user;
        } else {
            return userCache;
        }
    }

    private BaasUser getUserCache(String sessionToken) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String userStr = ops.get(USER_CLASS_NAME + "_" + sessionToken);
        BaasObject obj = JSON.parseObject(userStr, BaasObject.class);
        if (obj == null) {
            return null;
        } else {
            return new BaasUser(obj);
        }
    }

    private void setUserCache(String sessionToken, BaasUser user) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.set(USER_CLASS_NAME + "_" + sessionToken, JSON.toJSONString(user));
    }

    private void deleteUserCache(String sessionToken) {
        if (!StringUtils.isEmpty(sessionToken)) {
            redisTemplate.delete(USER_CLASS_NAME + "_" + sessionToken);
        }
    }

    public void deleteUser(String name) throws SimpleError {
        BaasQuery query = new BaasQuery();
        query.put("username", name);
        List<BaasObject> users = objectService.list(USER_CLASS_NAME, query, null, null, 1, 0, null, true);
        if (users.size() > 0) {
            String sessionToken = users.get(0).getString("sessionToken");
            deleteUserCache(sessionToken);
            objectService.delete(USER_CLASS_NAME, users.get(0).getString("id"), null, true);
        }
    }

    private String getSessionToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }

}
